#! /usr/bin/env python`

#-------------------------------------------#
#GeoStrike.pyw - a geometrical space shooter#
#By PyMike in May, 2008                     #
#Released under the GNU LGPL                #
#-------------------------------------------#

import pygame, math, random, os, pickle
from pygame.locals import *

os.environ["SDL_VIDEO_CENTERED"] = "1"
NO_POINTS = []
SHIP_POINTS = [(0, -10), (-15, 20), (0, 15), (15, 20)]
SHOT_POINTS = [(0, -7), (-2, 7), (0, 4), (2, 7)]
BIG_RECT = pygame.Rect((0,0,640,480))
global USE_AA
USE_AA = True



def __lineCollision(a, b):
    s1 = a[0]
    s2 = b[0]
    e1 = a[1]
    e2 = b[1]
    A = e1[0] - s1[0]
    B = e1[1] - s1[1]
    C = e2[0] - s2[0]
    D = e2[1] - s2[1]
    E = s1[1] - s2[1]
    F = s1[0] - s2[0]
 
    denom = (D*A)-(C*B)
    if denom == 0:
        return False
    numA = C*E - D*F
    numB = A*E - B*F

    Ta = numA / float(denom)
    Tb = numB / float(denom)

    return (Ta >= -0.5 and Ta <= 1) and (Tb >= -0.5 and Tb <= 1)

def Collision(obj1, obj2):
    l1 = xrange(len(obj1))
    l2 = xrange(len(obj2))
    for a in l1:
        for b in l2:
            if __lineCollision((obj1[a-1], obj1[a]),
                               (obj2[b-1], obj2[b])):
                return True
    return False


class Group(pygame.sprite.Group):
    def draw(self, surface):
        for s in self.sprites():
            s.draw(surface)

class VectorObject(pygame.sprite.Sprite):
    def __init__(self, points=NO_POINTS, pos=(0, 0), numpoints=None,
                 bake=False):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.points = points
        self.scale = 1.0
        self.angle = 0
        self.drawpoints = []
        self.pos = list(pos)
        self.velocity = [0, 0]
        self.color = (255, 255, 255)
        self.numpoints = numpoints
        self.rect = Rect(0, 0, 64, 64)
        self.rect.center = self.pos
        self.rotate_points()

    def update(self):
        self.pos[0] -= self.velocity[0]
        self.pos[1] -= self.velocity[1]
        self.rect.center = self.pos
        if not self.rect.colliderect(BIG_RECT):
            self.kill()

    def move(self, dx, dy):
        self.pos[0] += dx
        self.pos[1] += dy
        self.rect.center = self.pos

    def rotate_points(self):
        if self.numpoints:
            self.drawpoints = []
            numpoints = self.numpoints
            for i in xrange(numpoints):
                self.drawpoints.append([0,0])
            numpoints = numpoints
            for i in xrange(numpoints):
                angle = i*2*math.pi/numpoints
                self.drawpoints[i][0]=math.cos(angle - math.radians(self.angle))*25*self.scale + self.pos[0]
                self.drawpoints[i][1]=math.sin(angle - math.radians(self.angle))*25*self.scale + self.pos[1]
        else:
            self.drawpoints = []
            for p in self.points:
                newX = int(p[0]*math.cos(math.radians(-self.angle))*self.scale - p[1]*math.sin(math.radians(-self.angle))*self.scale + self.pos[0])
                newY = int(p[0]*math.sin(math.radians(-self.angle))*self.scale + p[1]*math.cos(math.radians(-self.angle))*self.scale + self.pos[1])
                self.drawpoints.append((newX,newY))

    def draw(self, surface):
        self.rotate_points()
#        pygame.draw.polygon(surface,self.color,self.drawpoints)
        if USE_AA:
            pygame.draw.aalines(surface,self.color,1,self.drawpoints)


class GameSpeed():
  def _init_(self):
      self.float = 100
  def update(self):
      key = pygame.key.get_pressed()
      if key[K_MINUS]:
        self.float = 50
      if key[K_EQUALS]:
        self.float = 1000


class Ship(VectorObject):
    def __init__(self):
        VectorObject.__init__(self, points=SHIP_POINTS, pos=(240, 450))
        self.color = (0, 255, 0)
        self.timer = 0
        self.level = 1
        self.shoot_sound = pygame.mixer.Sound(os.path.join("data", "shoot.ogg"))
    def update(self):
        if self.alive():
            key = pygame.key.get_pressed()
            self.timer += 1
            if key[K_LEFT]:
                self.move(-6, 0)
            if key[K_RIGHT]:
                self.move(6, 0)
            if self.pos[0] < 0:
                self.pos[0] = 0
            if self.pos[0] > 480:
                self.pos[0] = 480
            if True:
#            if key[K_SPACE]:
                if self.timer > 5:
                    self.shoot_sound.play()
                    if self.level > 1:
                        Shot(self.pos, -8, -3)
                        Shot(self.pos, 8, 3)
                        Shot(self.pos)
                    else:
                        Shot(self.pos, -8)
                        Shot(self.pos, 8)                    
                    self.timer = 0

class Shot(VectorObject):
    def __init__(self, pos, offset=0, speedoffset=0):
        VectorObject.__init__(self, points=SHOT_POINTS, pos=pos)
        self.move(offset, 5)
        self.vx = speedoffset

    def update(self):
        self.move(self.vx, -14)
        if self.pos[1] <= 0:
            self.kill()

class Tri(VectorObject):
    hp = 5
    def __init__(self, pos):
        VectorObject.__init__(self, numpoints=3, pos=pos)
        self.color = (0, 200, 255)
        self.vx = random.choice([0.25, 0.5, 0.75, 1.0])*2*random.choice([-1, 1])
        self.vy = random.choice([0.25, 0.5, 0.75, 1.0])*5
    def update(self):
        self.move(self.vx, self.vy)
        self.angle += 5*self.vx
        if self.pos[1] > 480:
            self.kill()
    def get_hit(self):
        self.hp -= 1
        if self.hp <= 0:
            self.kill()
            if self.scale == 1.0:
                for i in range(3):
                    t = Tri(self.pos)
                    t.scale = 0.5
                    t.hp = 2
            for i in range(15):
                Particle(self.pos)

class Hex(VectorObject):
    hp = 6
    def __init__(self, pos):
        VectorObject.__init__(self, numpoints=6, pos=pos)
        self.color = (255, 0, 255)
        self.vy = random.choice([0.25, 0.5, 0.75])*6
        self.frame = 0
    def update(self):
        self.move(0, self.vy)
        self.angle += math.sin(math.radians(self.frame))*5
        if self.pos[1] > 480:
            self.kill()
        self.frame += 5
        self.pos[0] += math.sin(math.radians(self.frame))*5
    def get_hit(self):
        self.hp -= 1
        if self.hp <= 0:
            self.kill()
            for i in range(15):
                Particle(self.pos)

class Square(VectorObject):
    hp = 12
    def __init__(self, pos):
        VectorObject.__init__(self, numpoints=4, pos=pos)
        self.color = (255, 255, 0)
        self.vy = random.choice([0.25, 0.5, 0.75])*6
        self.vx = self.vy
        self.frame = 0
    def update(self):
        self.angle += self.vx
        self.vx += random.choice([0.25, 0.5])*random.choice([-1, 1])
        self.vy += random.choice([0.25, 0.5])*random.choice([-1, 1])
        self.move(self.vx, self.vy)
        if self.pos[1] > 480:
            self.kill()
        if self.pos[0] > 480:
            self.kill()
        if self.pos[0] < 0:
            self.kill()
    def get_hit(self):
        self.hp -= 1
        if self.hp <= 0:
            self.kill()
            for i in range(15):
                Particle(self.pos)

class Octo(VectorObject):
    hp = 6
    def __init__(self, pos, target):
        VectorObject.__init__(self, numpoints=8, pos=pos)
        self.color = (255, 150, 0)
        self.vy = random.choice([0.25, 0.5, 0.75])*6
        self.vx = 0
        self.target = target
    def update(self):
        if self.pos[0] < self.target.pos[0] and self.vx < 5:
            self.vx += 0.25
        if self.pos[0] > self.target.pos[0] and self.vx > -5:
            self.vx -= 0.25
        self.move(self.vx, self.vy)
        self.angle += self.vx
        if self.pos[1] > 480:
            self.kill()
    def get_hit(self):
        self.hp -= 1
        if self.hp <= 0:
            self.kill()
            for i in range(15):
                Particle(self.pos)

class Particle(VectorObject):
    def __init__(self, pos):
        VectorObject.__init__(self, numpoints=10, pos=pos)
        self.size = random.randrange(1, 7)
        self.image = pygame.Surface((self.size, self.size))
        self.image.fill((255, 200, 0))
        self.angle = random.randrange(360)
        self.velocity = random.choice([0.1, 0.2, 0.3, 0.4, 0.5])*10
        self.alpha = 255

    def update(self):
        self.alpha -= 7
        if self.alpha <= 0:
            self.kill()
        self.move(math.sin(math.radians(self.angle))*self.velocity, math.cos(math.radians(self.angle))*self.velocity)
        self.image.set_alpha(self.alpha)
    def draw(self, surface):
        surface.blit(self.image, self.pos)

class Star(pygame.sprite.Sprite):

    def __init__(self):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.size = random.randrange(1, 4)
        self.image = pygame.Surface((self.size, self.size))
        self.pos = [random.randrange(480), random.randrange(480)]
        self.speed = random.choice([0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5])*3
        self.color = (self.speed*75, self.speed*75, self.speed*75)
        self.image.fill(self.color)
    def update(self):
        self.pos[1] += self.speed
        if self.pos[1] >= 480:
            self.pos[1] = 0
    def draw(self, surface):
        surface.blit(self.image, self.pos)




                
def Game(screen):

    stars = Group()
    all = Group()
    shots = Group()
    enemies = Group()
    particles = Group()
    bad = Group()
    Ship.containers = all
    Shot.containers = all, shots
    Tri.containers = all, enemies
    Hex.containers = all, enemies
    Square.containers = all, enemies
    Octo.containers = all, enemies
    Star.containers = stars
    Particle.containers = all, particles
    clock = pygame.time.Clock()
    ship = Ship()
    gamespeed = GameSpeed()
    gamespeed.float = 60
 #   score = 0
    level = 1
    lives = 1
    font = pygame.font.Font(os.path.join("data", "block.ttf"), 25)
    font2 = pygame.font.Font(os.path.join("data", "block.ttf"), 60)
    for i in range(75):
        Star()

    pygame.mixer.music.load(os.path.join("data", "Trance.ogg"))
    pygame.mixer.music.play(-1)
    boom_sound = pygame.mixer.Sound(os.path.join("data", "hit.ogg"))
    explode_sound = pygame.mixer.Sound(os.path.join("data", "explode.ogg"))
    timer = 150
#    highscores = Highscores()
    saved_score = False

    global USE_AA

    while 1:
        gamespeed.update()
#        clock.tick(1000)
        clock.tick(gamespeed.float)
        stars.update()
        if timer > 0:
            timer -= 1
#        if clock.get_fps() <= 30: #we're getting slow here - turn off aa!
#            USE_AA = False
#        else:
#            USE_AA = True

        events = pygame.event.get()
        for e in events:
            if e.type == QUIT:
                pygame.quit()
                return
            if e.type == KEYDOWN:
                if e.key == K_ESCAPE:
                    return

 #       level = int(score/500) + 1

        if timer <= 0:
 #           if level < 15:
                if not random.randrange(75 - (level*5)):
                    Tri((random.randrange(480), 0))
                if not random.randrange(100 - (level*5)):
                    Hex((random.randrange(480), 0))
                if not random.randrange(100 - (level*5)):
                   Square((random.randrange(480), 0))
                if not random.randrange(150 - (level*5)):
					Octo((random.randrange(480), 0), ship)
  #          else:
  #              if not random.randrange(5):
  #                  Tri((random.randrange(480), 0))
  #              if not random.randrange(5):
  #                  Hex((random.randrange(480), 0))
  #              if not random.randrange(5):
  #                  Square((random.randrange(480), 0))
  #              if not random.randrange(5):
  #                  Octo((random.randrange(480), 0), ship)

        for s in enemies.sprites():
            s.update()
            e = s
            for s in shots:
                if e.rect.colliderect(s.rect):
                    if Collision(e.drawpoints, s.drawpoints):
                        s.kill()
                        e.get_hit()
                        if e.hp <= 0:
                            explode_sound.play()
                        boom_sound.play()
                        Particle(s.pos)
 #                       score += 5
            if e.rect.colliderect(ship.rect):
                if Collision(e.drawpoints, ship.drawpoints) and ship.alive():
                    ship.kill()
                #    lives -= 1
                    explode_sound.play()
                    for i in xrange(200):
                        Particle(ship.pos)

        ship.update()
        for s in shots.sprites():
            s.update()

        particles.update()

        if not ship.alive() and lives > 0 and not particles:
            for s in all.sprites():
                s.kill()
            ship = Ship()

        screen.fill((0, 0, 0))
        stars.draw(screen)
        all.draw(screen)
  #      ren = font.render("Score: %06d" % score, 1, (150, 0, 150))
  #      screen.blit(ren, (11, 11))
 #       ren = font.render("Lives x%d" % lives, 1, (150, 0, 150))
  #      screen.blit(ren, (11, 36))
  #      ren = font.render("Level: %d" % level, 1, (150, 0, 150))
 #       screen.blit(ren, (241, 11))
        ren = font.render("FPS: %d" % clock.get_fps(), 1, (150, 0, 150))
        screen.blit(ren, (11, 11))
 #       ren = font.render("Score: %06d" % score, 1, (255, 200, 0))
 #       screen.blit(ren, (10, 10))
 #       ren = font.render("Lives x%d" % lives, 1, (255, 200, 0))
 #       screen.blit(ren, (10, 35))
 #       ren = font.render("Level: %d" % level, 1, (255, 200, 0))
 #       screen.blit(ren, (240, 10))
        ren = font.render("FPS: %d" % clock.get_fps(), 1, (255, 200, 0))
        screen.blit(ren, (10, 10))
        if lives <= 0:
            Game(screen)
        if timer > 75:
            ren = font2.render("Get Ready!", 1, (255, 255, 255))
            screen.blit(ren, (240-ren.get_width()/2, 240-ren.get_height()/2))
        if timer > 0 and timer <= 75:
            ren = font2.render("Go!", 1, (255, 255, 255))
            screen.blit(ren, (240-ren.get_width()/2, 240-ren.get_height()/2))
        pygame.display.flip()

def main():
    pygame.init()
    pygame.display.set_caption("GeoStrike - A geometrical shooter by PyMike")
    screen = pygame.display.set_mode((480, 480))
    pygame.mouse.set_visible(0)
#    Menu(screen)
    Game(screen)

if __name__ == "__main__":
    main()
